/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* 
 * gximprotocol.h
 * Copyright (C) 2008 Akira TAGOH
 * 
 * Authors:
 *   Akira TAGOH  <akira@tagoh.org>
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
#ifndef __G_XIM_PROTOCOL_H__
#define __G_XIM_PROTOCOL_H__

#include <glib.h>
#include <glib-object.h>
#include <gio/gio.h>
#include <gdk/gdk.h>
#include <libgxim/gximtypes.h>

G_BEGIN_DECLS

#define G_TYPE_XIM_PROTOCOL		(g_xim_protocol_get_type())
#define G_XIM_PROTOCOL(_o_)		(G_TYPE_CHECK_INSTANCE_CAST ((_o_), G_TYPE_XIM_PROTOCOL, GXimProtocol))
#define G_IS_XIM_PROTOCOL(_o_)		(G_TYPE_CHECK_INSTANCE_TYPE ((_o_), G_TYPE_XIM_PROTOCOL))
#define G_XIM_PROTOCOL_GET_IFACE(_o_)	(G_TYPE_INSTANCE_GET_INTERFACE ((_o_), G_TYPE_XIM_PROTOCOL, GXimProtocolIface))

#define G_XIM_PROTOCOL_ERROR		(g_xim_protocol_get_error_quark())

#define g_xim_protocol_n_pad4(_n_)	((4 - ((_n_) % 4)) % 4)
#define G_XIM_OPCODE_KEY(_m_,_n_)	GUINT_TO_POINTER ((_m_) << 8 | ((_n_) & 0xff))


/**
 * GXimProtocolIface:
 * @parent: a #GTypeInterface.
 *
 * An interface of XIM protocol.
 **/
typedef struct _GXimProtocolIface		GXimProtocolIface;
typedef struct _GXimProtocolPrivate		GXimProtocolPrivate;
typedef enum _GXimProtocolError			GXimProtocolError;

struct _GXimProtocolIface {
	GTypeInterface  parent_iface;

	GXimMessage    *message;
	GdkAtom         atom_xim_protocol;
	GdkAtom         atom_xim_moredata;

	/*< private >*/
	void (* reserved1) (void);
	void (* reserved2) (void);
	void (* reserved3) (void);
	void (* reserved4) (void);
	void (* reserved5) (void);
};

struct _GXimProtocolPrivate {
	GOutputStream        *base_send_ostream;
	GOutputStream        *base_recv_ostream;
	GDataOutputStream    *send_ostream;
	GDataOutputStream    *recv_ostream;
	GHashTable           *proto_table__named_index;
	GHashTable           *proto_table__id_index;
	GQueue               *markerq;
	GQueue               *syncableq;
	gulong                base_signal_ids[LAST_XIM_EVENTS];
	gulong                signal_ids[LAST_XIM_EVENTS];
	GDataStreamByteOrder  byte_order;
	gboolean              is_disconnected;
	/* XXX: workaround for failing to get the number of bytes written */
	gsize                 n_sent;
	gsize                 n_received;
};

enum _GXimProtocolError {
	G_XIM_PROTOCOL_ERROR_BEGIN = 128,
	G_XIM_PROTOCOL_ERROR_UNKNOWN_ENDIAN,
	G_XIM_PROTOCOL_ERROR_INVALID_PACKETS_RECEIVED,
	G_XIM_PROTOCOL_ERROR_DELIVERY_FAILURE,
	G_XIM_PROTOCOL_ERROR_NO_PARSER,
	G_XIM_PROTOCOL_ERROR_NO_DATA,
};


GType                g_xim_protocol_get_type               (void) G_GNUC_CONST;
void                 g_xim_protocol_init                   (GXimProtocol         *proto);
void                 g_xim_protocol_dispose                (GObject              *object);
void                 g_xim_protocol_finalize               (GObject              *object);
GXimProtocolPrivate *g_xim_protocol_get_private            (GXimProtocol         *proto);
GQuark               g_xim_protocol_get_error_quark        (void);
gboolean             g_xim_protocol_process_event          (GXimProtocol         *proto,
                                                            GdkEventClient       *event,
                                                            GError              **error);
gboolean             g_xim_protocol_translate              (GXimProtocol         *proto,
                                                            GError              **error);
gboolean             g_xim_protocol_send_packets           (GXimProtocol         *proto,
                                                            const gchar          *data,
                                                            gsize                 length);
gsize                g_xim_protocol_send_vformat           (GXimProtocol         *proto,
							    GCancellable         *cancellable,
							    GError              **error,
                                                            guint                 n_params,
                                                            va_list               args);
gsize                g_xim_protocol_send_format            (GXimProtocol         *proto,
							    GCancellable         *cancellable,
							    GError              **error,
                                                            guint                 n_params,
							    ...);
gboolean             g_xim_protocol_send                   (GXimProtocol         *proto,
                                                            GXimOpcode            major_opcode,
                                                            guint8                minor_opcode,
                                                            guint                 n_params,
							    ...);
gboolean             g_xim_protocol_send_with_list         (GXimProtocol         *proto,
                                                            GXimOpcode            major_opcode,
                                                            guint8                minor_opcode,
                                                            GSList               *types,
                                                            GSList               *values);
gboolean             g_xim_protocol_read_vformat           (GXimProtocol         *proto,
                                                            GDataInputStream     *stream,
                                                            GCancellable         *cancellable,
                                                            GError              **error,
                                                            guint                 n_params,
                                                            va_list               args);
gboolean             g_xim_protocol_read_format            (GXimProtocol         *proto,
                                                            GDataInputStream     *stream,
                                                            GCancellable         *cancellable,
                                                            GError              **error,
                                                            guint                 n_params,
							    ...);
gboolean             g_xim_protocol_wait_for_reply         (GXimProtocol         *proto,
                                                            GXimOpcode            major_opcode,
                                                            guint8                minor_opcode,
                                                            GError              **error);
void                 g_xim_protocol_add_protocol           (GXimProtocol         *proto,
                                                            GXimProtocolClosure  *closure);
void                 g_xim_protocol_remove_protocol        (GXimProtocol         *proto,
                                                            GXimProtocolClosure  *closure);
void                 g_xim_protocol_remove_protocol_by_id  (GXimProtocol         *proto,
                                                            guint8                major_opcode,
                                                            guint8                minor_opcode);
GXimProtocolClosure *g_xim_protocol_lookup_protocol_by_name(GXimProtocol         *proto,
                                                            const gchar          *name);
GXimProtocolClosure *g_xim_protocol_lookup_protocol_by_id  (GXimProtocol         *proto,
                                                            guint8                major_opcode,
                                                            guint8                minor_opcode);
gulong               g_xim_protocol_connect_closure_by_id  (GXimProtocol         *proto,
							    guint8                major_opcode,
							    guint8                minor_opcode,
							    GCallback             func,
							    gpointer              data);
gulong               g_xim_protocol_connect_closure_by_name(GXimProtocol         *proto,
							    const gchar          *signal_name,
							    GCallback             func,
							    gpointer              data);
GSList              *g_xim_protocol_get_extensions         (GXimProtocol         *proto);


/**
 * GXimProtocolClosure:
 *
 **/
typedef gboolean (* GXimProtocolClosureFunc)	(GXimProtocolClosure  *closure,
						 GXimProtocol         *proto,
						 GDataInputStream     *stream,
						 GError              **error,
						 gpointer              user_data);

struct _GXimProtocolClosure {
	GCClosure        closure;
	GClosureMarshal  signal_marshaller;
	guint            n_params;
	GType           *param_types;
	GSList          *signal_handlers;
	gchar           *name;
	union {
		GXimOpcode v1;
		guint8     v2;
	} major_opcode;
	guint8           minor_opcode;
	gboolean         is_an_extension;
};

GXimProtocolClosure *g_xim_protocol_closure_new            (guint8                   major_opcode,
							    guint8                   minor_opcode,
							    const gchar             *name,
							    gboolean                 is_an_extension);
void                 g_xim_protocol_closure_free           (gpointer                 data,
							    GClosure                *closure);
gboolean             g_xim_protocol_closure_is_an_extension(GXimProtocolClosure     *closure);
void                 g_xim_protocol_closure_set_marshal    (GXimProtocolClosure     *closure,
							    GXimProtocolClosureFunc  func,
							    gpointer                 data);
void                 g_xim_protocol_closure_add_signal     (GXimProtocolClosure     *closure,
							    GClosureMarshal          marshaller,
							    guint                    n_params,
							    ...);
gulong               g_xim_protocol_closure_connect        (GXimProtocolClosure     *closure,
							    GCallback                func,
							    gpointer                 data);
void                 g_xim_protocol_closure_disconnect     (GXimProtocolClosure     *closure,
							    gulong                   id);
gboolean             g_xim_protocol_closure_emit_signal    (GXimProtocolClosure     *closure,
							    GXimProtocol            *proto,
							    ...) G_GNUC_WARN_UNUSED_RESULT;

/**
 * GXimAttr:
 *
 **/
gsize    g_xim_attr_put_attribute_to_stream  (GXimProtocol      *proto,
                                              GXimAttr          *attr,
                                              guint              attribute_id,
                                              GCancellable      *cancellable,
                                              GError           **error);
gpointer g_xim_attr_get_attribute_from_stream(GXimProtocol      *proto,
                                              GXimAttr          *attr,
                                              GDataInputStream  *stream,
                                              GCancellable      *cancellable,
                                              GError           **error);


G_END_DECLS

#endif /* __G_XIM_PROTOCOL_H__ */
